package com.study.dynamic.context;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Configuration;

import java.util.Objects;

/**
 * @author Mayjean
 * @Date2020/9/10
 */
@Configuration
public class CustomApplicationContext implements ApplicationContextAware, BeanFactoryPostProcessor {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public <T> T getBean(String name, Class<T> clazz) {
        return applicationContext.getBean(name, clazz);
    }

    public <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }

    public <T> T registerBean(String name, Class<T> beanClass, Object... args) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(beanClass);
        if (Objects.nonNull(args) && args.length > 0) {
            for (Object arg : args) {
                beanDefinitionBuilder.addConstructorArgValue(arg);
            }
        }
        BeanDefinition beanDefinition = beanDefinitionBuilder.getRawBeanDefinition();

        BeanDefinitionRegistry beanDefinitionRegistry = getBean(BeanDefinitionRegistry.class);
        beanDefinitionRegistry.removeBeanDefinition(name);
        beanDefinitionRegistry.registerBeanDefinition(name, beanDefinition);

//        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(beanClass);
//        rootBeanDefinition.setSynthetic(true);
//        beanDefinitionRegistry.registerBeanDefinition(name, beanDefinition);


        return getBean(name, beanClass);
    }

    private DefaultListableBeanFactory defaultListableBeanFactory;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        this.defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory;
    }


    public void registerSingleton(String beanName ,Object singletonObject){
        defaultListableBeanFactory.destroySingleton(beanName);
        defaultListableBeanFactory.registerSingleton(beanName,singletonObject);
    }

    public void registerBeanDefinition(Class<?> beanClass){
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.rootBeanDefinition(beanClass);
        //用于设置指定的类中需要引入的其他bean
        //beanDefinitionBuilder.addPropertyValue("otherBeanName","otherBeanName");
        this.defaultListableBeanFactory.registerBeanDefinition(beanClass.getSimpleName(), beanDefinitionBuilder.getBeanDefinition());
    }
}